/*
 * 
 * ....................................................................
 * ...######..#####.....##....####..#####..####..#####..######....##...
 * .....##....##..#....###...##.....##.....##....##..#....##.....###...
 * .....##....####....#.##....##....####...####..####.....##....#.##...
 * .....##....##.#...#####.....##...##.....##....##.#.....##...#####...
 * .....##....##..#.#...##..####....##.....####..##..#....##..#...##...
 * ....................................................................
 */

package ua.trasferta.common.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import ua.trasferta.common.annotations.createBy;
import static ua.trasferta.common.team.TeamMember.*;
import static ua.trasferta.common.pattern.Pattern.*;

/**
 * Java class with static utility methods pertaining to {@link List} instances.
 * 
 * @NOTE this class inspired by <b>google-collections</b> and Joshua Bloch book.
 *       for effective programming.
 * @SEE http://code.google.com/p/google-collections/
 * @SEE {@link Sets}.
 * @SEE {@link Maps}.
 * @SEE http://code.google.com/p/trasferta/
 * @author Anton Podviaznikov
 */
@createBy(authors = ANTON_PODVIAZNIKOV)
public final class Lists
{
	/**
	 * Private constructor.
	 */
	private Lists()
	{
		// hidden constructor.
	}

	// ArrayList
	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @return a new, empty {@code ArrayList}.
	 */
	public static <E> ArrayList<E> newArrayList()
	{
		return new ArrayList<E>();
	}

	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @param elements - the elements that the list should contain.
	 * @return a new {@code ArrayList} containing those elements.
	 */
	public static <E> ArrayList<E> newArrayList(E... elements)
	{
		ArrayList<E> list = new ArrayList<E>(elements.length);
		Collections.addAll(list, elements);
		return list;
	}

	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @param elements - the elements that the list should contain
	 * @return a new {@code ArrayList} containing those elements.
	 */
	public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements)
	{
		if (elements instanceof Collection<?>)
		{
			Collection<? extends E> collection = (Collection<? extends E>)elements;
			return new ArrayList<E>(collection);
		}
		else
		{
			return Lists.newArrayList(elements.iterator());
		}
	}

	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @param elements - the elements that the list should contain.
	 * @return a new {@code ArrayList} containing those elements.
	 */
	public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements)
	{
		ArrayList<E> list = Lists.newArrayList();
		while (elements.hasNext())
		{
			list.add(elements.next());
		}
		return list;
	}

	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @param initialArraySize - the exact size of the initial backing array for
	 *            the returned array list ({@code ArrayList} documentation calls
	 *            this value the "capacity")
	 * @return a new, empty {@code ArrayList}.
	 * @throws IllegalArgumentException if {@code initialArraySize} is negative.
	 */
	public static <E> ArrayList<E> newArrayListWithCapacity(int initialArraySize)
	{
		return new ArrayList<E>(initialArraySize);
	}

	// LinkedList
	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @return a new, empty {@code LinkedList}.
	 */
	public static <E> LinkedList<E> newLinkedList()
	{
		return new LinkedList<E>();
	}

	/**
	 * If you don't want be confused {@link #FACTORY} pattern should be used.
	 * 
	 * @param elements - the elements that the list should contain.
	 * @return a new {@code LinkedList} containing those elements.
	 */
	public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements)
	{
		LinkedList<E> list = Lists.newLinkedList();
		for (E element : elements)
		{
			list.add(element);
		}
		return list;
	}
}